home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / CLASSSRC.PAK / TIME.CPP < prev    next >
C/C++ Source or Header  |  1997-05-06  |  8KB  |  281 lines

  1. //----------------------------------------------------------------------------
  2. // Borland Class Library
  3. // Copyright (c) 1993, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   5.7  $
  6. //
  7. // TTime class implementation
  8. //
  9. // Note: Be sure that you have set your environment variable TZ.
  10. //       For example, for Pacific coast time, set TZ=PDT8PST.
  11. //       For other time zones, see your manuals.
  12. //----------------------------------------------------------------------------
  13. #include <classlib/pch.h>
  14. #include <classlib/time.h>
  15. #include <services/checks.h>
  16. #include <time.h>
  17. #include <stdio.h>
  18.  
  19. enum TimeZone { CarolineIslands=-11,    MarianaIslands,         Japan,
  20.                 China,                  minusSeven,             minusSix,
  21.                 Pakistan,               CaspianSea,             Turkey,
  22.                 Finland,                Europe,                 Greenwich,
  23.                 Azores,                 two,                    Greenland,
  24.                 Atlantic,               USEastern,              USCentral,
  25.                 USMountain,             USPacific,              Alaska,
  26.                 Hawaii,                 Bearing};
  27.  
  28. static const unsigned long SECONDS_IN_DAY  = 86400L;
  29. static const unsigned long SECONDS_IN_HOUR = 3600L;
  30. static const unsigned      SECONDS_IN_MIN  = 60;
  31.  
  32. struct TInitTime
  33. {
  34.     TInitTime()
  35.         { tzset(); }
  36. };
  37.  
  38. static TInitTime cludgeTime;      // To force the call to tzset()
  39.  
  40.  
  41. const TDate TTime::RefDate( (DayTy)0, (YearTy)0 );
  42. const TDate TTime::MaxDate( (DayTy)49709L, (YearTy)0 ); // ((2**32)-1)/SECONDS_IN_DAY -1
  43. static const int SUNDAY = 7;
  44.  
  45. int TTime::AssertDate( const TDate _BIDSFAR & date )
  46. {
  47.     return date.Between(RefDate,MaxDate);
  48. }
  49.  
  50. //----------------------------------------------------------------------------
  51. //                     private member functions
  52.  
  53. //
  54. // Adjust for local time zone and Daylight Savings Time.
  55. //
  56. ClockTy TTime::LocalSecs() const
  57. {
  58.     TTime local_time( Sec - _timezone );
  59.     if (local_time.IsDST())
  60.         local_time.Sec += SECONDS_IN_HOUR;
  61.     return local_time.Sec;
  62. }
  63.  
  64. //
  65. // Builds the time from a local time, adjusting to GMT.  Does *not* adjust for DST.
  66. //
  67. TTime TTime::BuildLocal( const TDate _BIDSFAR & date, HourTy h )
  68. {
  69.     return TTime( SECONDS_IN_DAY * (date-RefDate) +
  70.                   SECONDS_IN_HOUR * h +
  71.                   _timezone);
  72. }
  73.  
  74. //----------------------------------------------------------------------------
  75. //                  public static member functions
  76.  
  77. //
  78. // Return the time at which DST starts for the given year.
  79. // Note that the time returned is the time at which DST starts locally,
  80. // but it is returned in GMT.
  81. //
  82. TTime TTime::BeginDST( unsigned year )
  83. {
  84.     if( year > 1986 )
  85.         {
  86.         TDate endMarch(31, 3, year);
  87.         return BuildLocal( endMarch.Previous(SUNDAY)+7, 2 );
  88.         }
  89.  
  90.     // Ah, remember those energy conscious years...???
  91.     if( year==1974 )
  92.         return BuildLocal( TDate(6,1,1974), 2 );
  93.     if( year==1975 )
  94.         return BuildLocal( TDate(23,2,1975), 2 );
  95.  
  96.     TDate endApril( 30, 4, year );
  97.     return BuildLocal( endApril.Previous(SUNDAY), 2 );
  98. }
  99.  
  100.  
  101. //
  102. // Return the time at which DST ends for the given year.
  103. // Note that the time returned is the time at which DST ends locally,
  104. // but it is returned in GMT.
  105. //
  106. TTime TTime::EndDST( unsigned year )
  107. {
  108.     TDate endOctober( 31, 10, year );
  109.     return BuildLocal( endOctober.Previous(SUNDAY), 1 );
  110. }
  111.  
  112.  
  113. //----------------------------------------------------------------------------
  114. //                            constructors
  115.  
  116. //
  117. // Construct TTime with current time (seconds since Jan 1, 1901).
  118. //
  119. TTime::TTime()
  120. {
  121.   time_t ltime;
  122.   time(<ime);
  123.   struct tm _FAR *t = localtime(<ime);
  124.  
  125.   // Construct the date.  The time struct returns int, so casts are used.
  126.   //
  127.   TDate today( (DayTy)t->tm_mday,
  128.                (MonthTy)(t->tm_mon + 1),
  129.                (YearTy)t->tm_year );
  130.  
  131.   *this = TTime( today,
  132.                  (HourTy)t->tm_hour,
  133.                  (MinuteTy)t->tm_min,
  134.                  (SecondTy)t->tm_sec );
  135. }
  136.  
  137. //
  138. // Specified time and today's date:
  139. //
  140. TTime::TTime( HourTy h, MinuteTy m, SecondTy s )
  141. {
  142.     Sec = TTime( TDate(),h,m,s ).Sec;
  143. }
  144.  
  145. //
  146. // Construct a Time for the specified (local) Date, hour, minute, and second.
  147. // Note: this algorithm will fail if DST correction is something other
  148. // than an hour.
  149. // It is complicated by the DST boundary problem:
  150. // 1) Times in the phantom zone between 2AM and 3AM when DST is invoked are invalid.
  151. // 2) Times in the hour after 1AM when DST ends, are redundant.
  152. // Checking for these situations necessitates a lot of jumping back
  153. // and forth by an hour to check for the boundary.
  154. //
  155. TTime::TTime( const TDate _BIDSFAR & date, HourTy h, MinuteTy m, SecondTy s )
  156. {
  157.     if( date.IsValid() )
  158.         {
  159.         Sec =   SECONDS_IN_DAY  * (date-RefDate) +
  160.                 SECONDS_IN_HOUR * (h-1L) +    /* Note the adjustment by one hour */
  161.                 SECONDS_IN_MIN  * m + s;
  162.         if( Sec )
  163.             Sec += _timezone;           // Adjust to GMT.
  164.  
  165.         if( IsDST() )
  166.             {
  167.             Sec += SECONDS_IN_HOUR;
  168.             if( IsDST() )
  169.                 Sec -= SECONDS_IN_HOUR;
  170.             }
  171.         else
  172.             {
  173.             Sec += SECONDS_IN_HOUR;
  174.             if( IsDST() )
  175.                 Sec = 0;            // Invalid "phantom" time.
  176.             }
  177.         }
  178.     else
  179.         Sec = 0;    // Invalid date
  180. }
  181.  
  182. //----------------------------------------------------------------------------
  183. //                  conversion from TTime to TDate
  184.  
  185. //
  186. // Type conversion to date.
  187. //
  188. TDate::TDate( const TTime _BIDSFAR & t )
  189. {
  190.     Julnum = t.IsValid() ? jul1901 + (JulTy)(t.LocalSecs()/SECONDS_IN_DAY) : 0;
  191. }
  192.  
  193. //----------------------------------------------------------------------------
  194. //                     public member functions
  195.  
  196. int TTime::CompareTo( const TTime _BIDSFAR &t ) const
  197. {
  198.     ClockTy diff = Sec - t.Sec;
  199.     return diff==0 ? 0 : diff>0 ? 1 : -1;
  200. }
  201.  
  202. //
  203. // Hash function:
  204. //
  205. unsigned TTime::Hash() const
  206. {
  207.     return (unsigned)Sec;
  208. }
  209.  
  210. //
  211. // The hour in local time:
  212. //
  213. HourTy TTime::Hour() const
  214. {
  215.     return HourTy((LocalSecs() % SECONDS_IN_DAY) / SECONDS_IN_HOUR);
  216. }
  217.  
  218. //
  219. // The hour in GMT:
  220. //
  221. HourTy TTime::HourGMT() const
  222. {
  223.     return HourTy((Sec % SECONDS_IN_DAY) / SECONDS_IN_HOUR);
  224. }
  225.  
  226. //
  227. // Return TRUE if DST is active for this time:
  228. //
  229. int TTime::IsDST() const
  230. {
  231.   if( !_daylight )
  232.     return 0;
  233.  
  234.   DayTy daycount = (unsigned)(Sec/SECONDS_IN_DAY);
  235.   YearTy year = TDate( (DayTy)daycount, (YearTy)0 ).Year();
  236.  
  237.   // Check to see if the time falls between the starting & stopping DST times.
  238.   //
  239.   return *this >= BeginDST( year ) && *this < EndDST( year );
  240. }
  241.  
  242. TTime TTime::Max( const TTime _BIDSFAR & t ) const
  243. {
  244.     if( *this > t )
  245.         return *this;
  246.     else
  247.         return t;
  248. }
  249.  
  250. TTime TTime::Min( const TTime _BIDSFAR & t ) const
  251. {
  252.     if( *this < t )
  253.         return *this;
  254.     else
  255.         return t;
  256. }
  257.  
  258. //
  259. // minute, in local time
  260. //
  261. MinuteTy TTime::Minute() const
  262. {
  263.     return MinuteTy(((LocalSecs()%SECONDS_IN_DAY)%SECONDS_IN_HOUR)/SECONDS_IN_MIN);
  264. }
  265.  
  266. //
  267. // minute, in GMT
  268. //
  269. MinuteTy TTime::MinuteGMT() const
  270. {
  271.     return MinuteTy(((Sec%SECONDS_IN_DAY)%SECONDS_IN_HOUR)/SECONDS_IN_MIN);
  272. }
  273.  
  274. //
  275. // second, in local time or GMT
  276. //
  277. SecondTy TTime::Second() const
  278. {
  279.     return SecondTy(((Sec%SECONDS_IN_DAY)%SECONDS_IN_HOUR)%SECONDS_IN_MIN);
  280. }
  281.